/*
** $身份: 嘞非转储.c $
** 加载预编译的炉啊大块
** 参见 炉啊.h 版权声明
*
* * 本人所用声母表: a啊 b哔 c西 d迪 e鹅 f弗 g哥 
* h喝 i艾 j鸡 k颗 l嘞 m摸 n恩
* o欧 p匹 q气 r日 s丝 t嚏 
* u由 v微 w屋 x斯 y医 z只
*
* 一些英文单词缩写,我的翻译大多来自;有道词典,谷歌翻译,百度.
* 一些术语实在不好翻译,所以就原封不动.
* 
* 一些特有的表示特有库的术语是无法翻译的 *
* 否则编译器不能识别不能通过,第一版汉化就行不通.
*
* 
*/


#define 嘞非转储_西
#define 炉啊_核心

#include "嘞前缀.h"


#include <limits.h>
#include <string.h>

#include "炉啊.h"

#include "嘞调试.h"
#include "嘞做.h"
#include "嘞函.h"
#include "嘞内存.h"
#include "嘞对象.h"
#include "嘞串.h"
#include "嘞非转储.h"
#include "嘞只入出.h"

#if !defined(炉啊艾_验证码)
#define 炉啊艾_验证码(嘞,弗)  /* 空 */
#endif

typedef struct {
  炉啊_国 *嘞;
  只入出 *只;
  const char *名字;
} 加载国;


static 嘞_不返回 错误 (加载国 *丝, const char *为啥) {
  炉啊欧_推弗串(丝->嘞, "%s: 差劲二进制格式 (%s)", 丝->名字, 为啥);
  炉啊迪_抛(丝->嘞, 炉啊_错句法);
}

/*
** 所有高级加载都通过 加载矢量; 您可以更改它以适应输入的字节序
*/


#define 加载矢量(丝,哔,恩)	加载块(丝,哔,(恩)*sizeof((哔)[0]))

static void 加载块 (加载国 *丝, void *哔, size_t 大小) {
  if (炉啊只_读(丝->只, 哔, 大小) != 0)
    错误(丝, "截断 大块");
}

#define 加载变量(丝,斯)		加载矢量(丝,&斯,1)


static 炉_字节 加载字节 (加载国 *丝) {
  int 哔 = 只取西(丝->只);
  if (哔 == EOZ)
    错误(丝, "截断 大块");
  return 投_字节(哔);
}

static size_t 加载无符号 (加载国 *丝, size_t 极限) {
  size_t 斯 = 0;
  int 哔;
  极限 >>= 7;
  do {
    哔 = 加载字节(丝);
    if (斯 >= 极限)
      错误(丝, "整数 溢出");
    斯 = (斯 << 7) | (哔 & 0x7f);
  } while ((哔 & 0x80) == 0);
  return 斯;
}

static size_t 加载大小 (加载国 *丝) {
  return 加载无符号(丝, ~(size_t)0);
}


static int 加载整型 (加载国 *丝) {
  return 投_整型(加载无符号(丝, 整型_最大));
}

static 炉啊_号码 加载号码 (加载国 *丝) {
  炉啊_号码 斯;
  加载变量(丝, 斯);
  return 斯;
}


static 炉啊_整数 加载整数 (加载国 *丝) {
  炉啊_整数 斯;
  加载变量(丝, 斯);
  return 斯;
}

/*
** 将一个可空串加载到原型 '匹'.
*/


static 嚏串 *加载串恩 (加载国 *丝, 原型 *匹) {
  炉啊_国 *嘞 = 丝->嘞;
  嚏串 *嚏丝;
  size_t 大小 = 加载大小(丝);
  if (大小 == 0)  /* 没串? */
    return NULL;
  else if (--大小 <= 炉啊艾_最大短长度) {  /* 短串? */
    char 缓冲[炉啊艾_最大短长度];
    加载矢量(丝, 缓冲, 大小);  /* 加载串进缓冲 */
    嚏丝 = 炉啊丝_新嘞串(嘞, 缓冲, 大小);  /* 创建串 */
  }
  else {  /* 长串 */
    嚏丝 = 炉啊丝_创建长串对象(嘞, 大小);  /* 创建串 */
    加载矢量(丝, 取串(嚏丝), 大小);  /* 最后位置直接加载 */
  }
  炉啊西_对象障碍(嘞, 匹, 嚏丝);
  return 嚏丝;
}


/*
** 加载非无效串进原型 '匹'.
*/

static 嚏串 *加载串 (加载国 *丝, 原型 *匹) {
  嚏串 *丝嚏 = 加载串恩(丝, 匹);
  if (丝嚏 == NULL)
    错误(丝, "常量串的差劲格式");
  return 丝嚏;
}

static void 加载代码 (加载国 *丝, 原型 *弗) {
  int 恩 = 加载整型(丝);
  弗->代码 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 指令);
  弗->大小代码 = 恩;
  加载矢量(丝, 弗->代码, 恩);
}


static void 加载函数(加载国 *丝, 原型 *弗, 嚏串 *匹源码);

static void 加载常量 (加载国 *丝, 原型 *弗) {
  int 艾;
  int 恩 = 加载整型(丝);
  弗->颗 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 嚏值);
  弗->大小颗 = 恩;
  for (艾 = 0; 艾 < 恩; 艾++)
    设置零值(&弗->颗[艾]);
  for (艾 = 0; 艾 < 恩; 艾++) {
    嚏值 *欧 = &弗->颗[艾];
    int 嚏 = 加载字节(丝);
    switch (嚏) {
      case 炉啊_微零:
        设置零值(欧);
        break;
      case 炉啊_微假:
        设置哔弗值(欧);
        break;
      case 炉啊_微真:
        设置哔嚏值(欧);
        break;
      case 炉啊_微号浮:
        设置浮值(欧, 加载号码(丝));
        break;
      case 炉啊_微号整:
        设置艾值(欧, 加载整数(丝));
        break;
      case 炉啊_微短串:
      case 炉啊_微长串:
        设置丝值到恩(丝->嘞, 欧, 加载串(丝, 弗));
        break;
      default: 炉啊_断言(0);
    }
  }
}

static void 加载原型 (加载国 *丝, 原型 *弗) {
  int 艾;
  int 恩 = 加载整型(丝);
  弗->匹 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 原型 *);
  弗->大小匹 = 恩;
  for (艾 = 0; 艾 < 恩; 艾++)
    弗->匹[艾] = NULL;
  for (艾 = 0; 艾 < 恩; 艾++) {
    弗->匹[艾] = 炉啊弗_新原型(丝->嘞);
    炉啊西_对象障碍(丝->嘞, 弗, 弗->匹[艾]);
    加载函数(丝, 弗->匹[艾], 弗->源码);
  }
}


static void 加载上值 (加载国 *丝, 原型 *弗) {
  int 艾, 恩;
  恩 = 加载整型(丝);
  弗->上值 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 上值描述);
  弗->大小上值 = 恩;
  for (艾 = 0; 艾 < 恩; 艾++) {
    弗->上值[艾].名字 = NULL;
    弗->上值[艾].栈内 = 加载字节(丝);
    弗->上值[艾].索引 = 加载字节(丝);
    弗->上值[艾].种类 = 加载字节(丝);
  }
}

static void 加载调试 (加载国 *丝, 原型 *弗) {
  int 艾, 恩;
  恩 = 加载整型(丝);
  弗->行信息 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 嘞丝_字节);
  弗->大小行信息 = 恩;
  加载矢量(丝, 弗->行信息, 恩);
  恩 = 加载整型(丝);
  弗->绝对行信息 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 绝对行信息);
  弗->大小绝对行信息 = 恩;
  for (艾 = 0; 艾 < 恩; 艾++) {
    弗->绝对行信息[艾].程序计数 = 加载整型(丝);
    弗->绝对行信息[艾].行 = 加载整型(丝);
  }
  恩 = 加载整型(丝);
  弗->本地变量 = 炉啊摸_新矢量已检查(丝->嘞, 恩, 本地变量);
  弗->大小本地变量 = 恩;
  for (艾 = 0; 艾 < 恩; 艾++)
    弗->本地变量[艾].变量名 = NULL;
  for (艾 = 0; 艾 < 恩; 艾++) {
    弗->本地变量[艾].变量名 = 加载串恩(丝, 弗);
    弗->本地变量[艾].开始程序计数 = 加载整型(丝);
    弗->本地变量[艾].终程序计数 = 加载整型(丝);
  }
  恩 = 加载整型(丝);
  for (艾 = 0; 艾 < 恩; 艾++)
    弗->上值[艾].名字 = 加载串恩(丝, 弗);
}


static void 加载函数 (加载国 *丝, 原型 *弗, 嚏串 *匹源码) {
  弗->源码 = 加载串恩(丝, 弗);
  if (弗->源码 == NULL)  /* 转储中没有源? */
    弗->源码 = 匹源码;  /* 重用父类的源 */
  弗->行已定义 = 加载整型(丝);
  弗->最后行已定义 = 加载整型(丝);
  弗->号形参 = 加载字节(丝);
  弗->是否_变量实参 = 加载字节(丝);
  弗->最大栈大小 = 加载字节(丝);
  加载代码(丝, 弗);
  加载常量(丝, 弗);
  加载上值(丝, 弗);
  加载原型(丝, 弗);
  加载调试(丝, 弗);
}

static void 检查字面 (加载国 *丝, const char *小丝, const char *消息) {
  char 缓冲[sizeof(炉啊_签名) + sizeof(炉啊西_数据)]; /* 大于两个 */
  size_t 长度 = strlen(小丝);
  加载矢量(丝, 缓冲, 长度);
  if (memcmp(小丝, 缓冲, 长度) != 0)
    错误(丝, 消息);
}

static void 弗检查大小 (加载国 *丝, size_t 大小, const char *嚏名字) {
  if (加载字节(丝) != 大小)
    错误(丝, 炉啊欧_推弗串(丝->嘞, "%s 大小 不匹配", 嚏名字));
}

#define 检查大小(丝,嚏)	弗检查大小(丝,sizeof(嚏),#嚏)

static void 检查头部 (加载国 *丝) {
  /* 跳过第一个印刻 (已阅读并检查) */
  检查字面(丝, &炉啊_签名[1], "非二进制块");
  if (加载字节(丝) != 炉啊西_版本)
    错误(丝, "版本不匹配");
  if (加载字节(丝) != 炉啊西_格式)
    错误(丝, "格式不匹配");
  检查字面(丝, 炉啊西_数据, "损坏的块");
  检查大小(丝, 指令);
  检查大小(丝, 炉啊_整数);
  检查大小(丝, 炉啊_号码);
  if (加载整数(丝) != 炉啊西_整型)
    错误(丝, "整数格式不匹配");
  if (加载号码(丝) != 炉啊西_号)
    错误(丝, "浮点数格式不匹配");
}


/*
** 加载预编译的块.
*/
嘞闭包 *炉啊由_非转储(炉啊_国 *嘞, 只入出 *只, const char *名字) {
  加载国 丝;
  嘞闭包 *闭包;
  if (*名字 == '@' || *名字 == '=')
    丝.名字 = 名字 + 1;
  else if (*名字 == 炉啊_签名[0])
    丝.名字 = "二进制串";
  else
    丝.名字 = 名字;
  丝.嘞 = 嘞;
  丝.只 = 只;
  检查头部(&丝);
  闭包 = 炉啊弗_新嘞闭包(嘞, 加载字节(&丝));
  设置闭包嘞值到丝(嘞, 嘞->顶部, 闭包);
  炉啊迪_增顶部(嘞);
  闭包->匹 = 炉啊弗_新原型(嘞);
  炉啊西_对象障碍(嘞, 闭包, 闭包->匹);
  加载函数(&丝, 闭包->匹, NULL);
  炉啊_断言(闭包->恩上值 == 闭包->匹->大小上值);
  炉啊艾_验证码(嘞, 闭包->匹);
  return 闭包;
}